package org.linlinjava.litemall.core.payment.clover.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.SneakyThrows;
import okhttp3.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.core.constant.LitemallWXMembershipLevelConstants;
import org.linlinjava.litemall.core.constant.LumiereCloverAPIConstant;
import org.linlinjava.litemall.core.constant.LumiereCloverConstant;
import org.linlinjava.litemall.core.notify.NoticeHelper;
import org.linlinjava.litemall.core.notify.PosPushSender;
import org.linlinjava.litemall.core.payment.DefaultCurType;
import org.linlinjava.litemall.core.payment.PaymentResponseCode;
import org.linlinjava.litemall.core.payment.clover.config.CloverConfig;
import org.linlinjava.litemall.core.payment.clover.dto.ApiChargeDTO;
import org.linlinjava.litemall.core.payment.clover.rq.*;
import org.linlinjava.litemall.core.payment.clover.rs.*;
import org.linlinjava.litemall.core.payment.clover.service.CloverService;
import org.linlinjava.litemall.core.payment.clover.service.CloverTokenManager;
import org.linlinjava.litemall.core.payment.clover.vo.CardInfoReqVO;
import org.linlinjava.litemall.core.util.AdminCouponDateUtil;
import org.linlinjava.litemall.core.util.GeneratorUtil;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.beans.Constants;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.dto.CloverChargesDTO;
import org.linlinjava.litemall.db.dto.CloverCustomerCreateDTO;
import org.linlinjava.litemall.db.dto.CloverCustomerDTO;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.service.LitemallOrderService;
import org.linlinjava.litemall.db.util.OrderStatusUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static org.linlinjava.litemall.db.beans.Constants.MEMBER_STATUS_INUSE;

@Service
@Transactional
public class GoodsCloverServiceImpl implements CloverService {
    private final Log logger = LogFactory.getLog(GoodsCloverServiceImpl.class);

    @Autowired
    private LitemallOrderService orderService;

    @Autowired
    private PosPushSender posPushSender;

    @Autowired
    private LitemallUserService litemallUserService;

    @Autowired
    private NoticeHelper noticeHelper;

    @Autowired
    private LumierePayMemberService lumierePayMemberService;

    @Autowired
    private LumierePayMemberUserService lumierePayMemberUserService;

    @Autowired
    private LumierelLevelMemberService lumierelLevelMemberService;

    @Autowired
    private LumiereLevelMemberPointService lumiereLevelMemberPointService;

    @Autowired
    private LumiereMemberWelfareCouponService lumiereMemberWelfareCouponService;

    @Autowired
    private LitemallCouponService litemallCouponService;

    @Autowired
    private LitemallIntegralLogService integralLogService;

    @Autowired
    private LitemallUserService userService;

    @Autowired
    private LitemallCouponUserService litemallCouponUserService;
    @Autowired
    private CloverConfig cloverConfig;
    @Autowired
    private LumiereMemberWelfareSubscribeService lumiereMemberWelfareSubscribeService;
    @Autowired
    private LumiereSubscribeUserService lumiereSubscribeUserService;
    @Autowired
    private LitemallGiftCardUserService litemallGiftCardUserService;
    @Autowired
    private LitemallGiftCardService litemallGiftCardService;
    @Autowired
    private LumiereSubscribeRuleService lumiereSubscribeRuleService;

    @Autowired
    private LitemallShopRegionService shopRegionService;

    @Autowired
    private LitemallRegionService regionService;

    @Autowired LumiereCloverCodeService lumiereCloverCodeService;

    @Autowired
    private LumiereCloverCardService lumiereCloverCardService;

    @Autowired
    private LumiereCloverPayLogService lumiereCloverPayLogService;

    @Autowired
    private LumiereCloverChargesLogService lumiereCloverChargesLogService;

    @Autowired
    private LumiereCouponUserService lumiereCouponUserService;

    @Autowired
    private LumiereCouponStrategyService lumiereCouponStrategyService;

    @Autowired
    private LumiereCloverCardInfoService lumiereCloverCardInfoService;

    @SneakyThrows
    public Object acquireCode(String merchantId, String employeeId, String clientId, String code) {
        //请求acces_token|刷新令牌
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(String.format(LumiereCloverAPIConstant.CLOVER_ACQUIRECODE,clientId,cloverConfig.getClientSecret(),code))
                .get()
                .build();
        Response response = client.newCall(request).execute();
        JSONObject result = (JSONObject) JSON.parse(response.body().string());
        Snowflake snowflake = IdUtil.createSnowflake(1, 1);
        if(StrUtil.isNotBlank(result.getString("message"))){
            return ResponseUtil.fail(result.getString("message"));
        }
        //保存所有数据
        LumiereCloverCode cloverCode = LumiereCloverCode.builder()
                .id(snowflake.nextId())
                .merchantId(merchantId)
                .employeeId(employeeId)
                .clientId(clientId)
                .code(code)
                .accessToken(result.getString("access_token"))
                .addTime(LocalDateTime.now())
                .build();
        boolean save = lumiereCloverCodeService.save(cloverCode);
        return save?ResponseUtil.ok(cloverCode):ResponseUtil.fail("令牌刷新失败!");
    }
    @SneakyThrows
    @Override
    public List<ApiCustomerRS> getCustomerCards(String customerId)  {
        //获取客户保存的所有卡
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(String.format(LumiereCloverAPIConstant.CLOVER_GETCUSTOMERCARDS,cloverConfig.getMerchantId(),customerId,"=cards%2Caddresses"))
                .get()
                .addHeader(LumiereCloverConstant.ACCEPT, LumiereCloverConstant.APPLICATIONJSON)
                .addHeader(LumiereCloverConstant.AUTHORIZATION, String.format(LumiereCloverConstant.BEARER,cloverConfig.getAccessToken()))
                .build();

        Response response = client.newCall(request).execute();
        JSONObject jo = JSON.parseObject(response.body().string());
        if(StrUtil.isBlank(jo.getJSONObject("cards").toJSONString())){return CollUtil.newArrayList();}
        //获得卡列表
        JSONArray array = JSON.parseArray(jo.getJSONObject("cards").getString("elements"));
        List<ApiCustomerRS> apiCustomerRSList = array.stream().map(element -> {
            JSONObject job = (JSONObject) element;
            ApiCustomerRS customerRS = new ApiCustomerRS();
            customerRS.setId(job.getString("id"));
            customerRS.setLast4(job.getString("last4"));
            customerRS.setFirst6(job.getString("first6"));
            customerRS.setCardType(job.getString("cardType"));
            customerRS.setExpirationDate(job.getString("modifiedTime"));
            customerRS.setToken(customerId);
            if (customerRS != null && customerRS.getExpirationDate() != null) {
                // 将时间戳转换为 Date 对象
                Date date = DateUtil.date(Long.valueOf(customerRS.getExpirationDate()));
                // 获取年份和月份
                customerRS.setMonth(String.valueOf(DateUtil.year(date)));
                customerRS.setYear(String.valueOf(DateUtil.month(date) + 1));
            }
            return customerRS;
        }).collect(Collectors.toList());
        return apiCustomerRSList;
    }

    @SneakyThrows
    public ResponseUtil.Response appendCustomer(Integer userId,String token,String customerId)  {
        LitemallUser litemallUser = litemallUserService.findById(userId);
        //后面再判断是否重复添加过
        boolean exist = getCustomerCards(customerId).stream().anyMatch(customerCard -> customerCard.getToken().equals(token));
        if(exist){
            //重复绑卡
            return ResponseUtil.fail(10021, "添加卡失败,卡重复绑定");
        }
        //为现有客户保存卡片
        OkHttpClient client = new OkHttpClient();
        ApiCustomerRQ apiCustomerRQ = new ApiCustomerRQ();
        apiCustomerRQ.setEmail(litemallUser.getEmail());
        apiCustomerRQ.setSource(token);

        MediaType mediaType = MediaType.parse(LumiereCloverConstant.APPLICATIONJSON);
        RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(apiCustomerRQ));
        Request request = new Request.Builder()
                .url(String.format(LumiereCloverAPIConstant.CLOVER_APPENDCUSTOMER,customerId))
                .put(body)
                .addHeader(LumiereCloverConstant.ACCEPT,LumiereCloverConstant.APPLICATIONJSON)
                .addHeader(LumiereCloverConstant.CONTENTTYPE, LumiereCloverConstant.APPLICATIONJSON)
                .addHeader(LumiereCloverConstant.AUTHORIZATION, String.format(LumiereCloverConstant.BEARER,cloverConfig.getAccessToken()))
                .build();

        Response response = client.newCall(request).execute();
        JSONObject jsonObject =  JSON.parseObject(response.body().string());
        CloverCustomerDTO customer = JSON.toJavaObject(jsonObject,CloverCustomerDTO.class);
        return customer.getId() != null?ResponseUtil.ok(customer):
                ResponseUtil.fail(917, "添加卡失败,请仔细核对信息");
    }

    @SneakyThrows
    public ResponseUtil.Response createCustomer(Integer userId, CardInfoReqVO cardInfo, LumiereCloverCard customer){
        LitemallUser litemallUser = litemallUserService.findById(userId);
        if(ObjectUtil.isNull(customer)){
            //开始创建新客户
            OkHttpClient client = new OkHttpClient();
            ApiCustomerCreateRQ apiCustomerCreateRQ = new ApiCustomerCreateRQ();
            apiCustomerCreateRQ.setFirstName(StrUtil.sub(litemallUser.getUsername(), 0, 6));
            apiCustomerCreateRQ.setLastName(StrUtil.sub(litemallUser.getUsername(), litemallUser.getUsername().length() - 4, litemallUser.getUsername().length()));

            MediaType mediaType = MediaType.parse("application/json");
            RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(apiCustomerCreateRQ));
            Request request = new Request.Builder()
                    .url(String.format(LumiereCloverAPIConstant.CLOVER_CREATECUSTOMER,cloverConfig.getMerchantId()))
                    .post(body)
                    .addHeader(LumiereCloverConstant.ACCEPT,LumiereCloverConstant.APPLICATIONJSON)
                    .addHeader(LumiereCloverConstant.AUTHORIZATION, String.format(LumiereCloverConstant.BEARER,cloverConfig.getAccessToken()))
                    .addHeader(LumiereCloverConstant.CONTENTTYPE, LumiereCloverConstant.APPLICATIONJSON)
                    .build();

            Response response = client.newCall(request).execute();
            JSONObject jsonObject = JSON.parseObject(response.body().string());
            CloverCustomerCreateDTO customerCreate= JSON.toJavaObject(jsonObject, CloverCustomerCreateDTO.class);
            if(StrUtil.isBlank(customerCreate.getId())){return ResponseUtil.fail(915, "商家令牌失效或其它原因");}
            LumiereCloverCard cloverCard = new LumiereCloverCard();
            cloverCard.setUserId(userId);
            cloverCard.setCustomerId(customerCreate.getId());
            cloverCard.setUpdateTime(LocalDateTime.now());
            cloverCard.setAddTime(LocalDateTime.now());
            cloverCard.setDeleted(false);
            lumiereCloverCardService.insert(cloverCard);
            customer = cloverCard;
        }

        //为用户绑定卡
        createCustomerCards(customer.getCustomerId(), litemallUser, cardInfo);
        return ResponseUtil.ok("添加成功");
    }

    @SneakyThrows
    public ResponseUtil.Response createCustomer(Integer userId, String token){
        LitemallUser litemallUser = litemallUserService.findById(userId);
        //开始为新客户保存卡片
        OkHttpClient client = new OkHttpClient();
        ApiCustomerRQ apiCustomerRQ = new ApiCustomerRQ();
        apiCustomerRQ.setEmail(litemallUser.getEmail());
        apiCustomerRQ.setSource(token);

        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(apiCustomerRQ));
        Request request = new Request.Builder()
                .url(LumiereCloverAPIConstant.CLOVER_CREATECUSTOMER)
                .post(body)
                .addHeader(LumiereCloverConstant.ACCEPT,LumiereCloverConstant.APPLICATIONJSON)
                .addHeader(LumiereCloverConstant.AUTHORIZATION, String.format(LumiereCloverConstant.BEARER,cloverConfig.getAccessToken()))
                .addHeader(LumiereCloverConstant.CONTENTTYPE, LumiereCloverConstant.APPLICATIONJSON)
                .build();

        Response response = client.newCall(request).execute();
        JSONObject jsonObject = JSON.parseObject(response.body().string());
        CloverCustomerDTO customer= JSON.toJavaObject(jsonObject,CloverCustomerDTO.class);
        if(StrUtil.isBlank(customer.getId())){return ResponseUtil.fail(915, "商家令牌失效或其它原因");}
        LumiereCloverCard cloverCard = new LumiereCloverCard();
        cloverCard.setUserId(userId);
        cloverCard.setCustomerId(customer.getId());
        cloverCard.setUpdateTime(LocalDateTime.now());
        cloverCard.setAddTime(LocalDateTime.now());
        cloverCard.setDeleted(false);
        lumiereCloverCardService.insert(cloverCard);
        return ResponseUtil.ok("添加成功");
    }

    @SneakyThrows
    public ResponseUtil.Response createCustomerCards(String customerId, LitemallUser user ,CardInfoReqVO cardInfo){
        if(StrUtil.isBlank(user.getEmail())){return ResponseUtil.fail(916, "用户邮箱不可为空！");}
        //开始为新客户保存卡片
        OkHttpClient client = new OkHttpClient();
        ApiCustomerRQ apiCustomerRQ = new ApiCustomerRQ();
        apiCustomerRQ.setEmail(user.getEmail());
        apiCustomerRQ.setSource(cardInfo.getToken());
        apiCustomerRQ.setFirst6(cardInfo.getFirst6());
        apiCustomerRQ.setLast4(cardInfo.getLast4());
        apiCustomerRQ.setCardType(cardInfo.getBrand());


        // 处理月份，如果是一位数则前面补 0
        String formattedMonth;
        if (cardInfo.getExpMonth().length() == 1) {
            formattedMonth = "0" + cardInfo.getExpMonth();
        } else {
            formattedMonth = cardInfo.getExpMonth();
        }

        // 获取年份的后两位
        String yearLastTwoDigits = cardInfo.getExpYear().substring(2);

        // 拼接月份和年份的后两位
        String expirationDate = formattedMonth + yearLastTwoDigits;

        // 设置过期日期
        apiCustomerRQ.setExpirationDate(expirationDate);
        apiCustomerRQ.setToken(cardInfo.getToken());
        apiCustomerRQ.getAdditionalInfo().setZip(cardInfo.getAddressZip());

        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(apiCustomerRQ));
        Request request = new Request.Builder()
                .url(String.format(LumiereCloverAPIConstant.CLOVER_CREATE_CUSTOMER_CARDS,cloverConfig.getMerchantId(),customerId))
                .post(body)
                .addHeader(LumiereCloverConstant.ACCEPT,LumiereCloverConstant.APPLICATIONJSON)
                .addHeader(LumiereCloverConstant.AUTHORIZATION, String.format(LumiereCloverConstant.BEARER,cloverConfig.getAccessToken()))
                .addHeader(LumiereCloverConstant.CONTENTTYPE, LumiereCloverConstant.APPLICATIONJSON)
                .build();

        Response response = client.newCall(request).execute();
        JSONObject jsonObject = JSON.parseObject(response.body().string());
        CloverCustomerDTO customer= JSON.toJavaObject(jsonObject,CloverCustomerDTO.class);
        if(StrUtil.isBlank(customer.getId())){return ResponseUtil.fail(915, "商家令牌失效或其它原因");}
        //记录数据库
        LumiereCloverCardInfo cloverCardInfo = new LumiereCloverCardInfo();
        cloverCardInfo.setCardId(customer.getId());
        cloverCardInfo.setUserId(user.getId());
        cloverCardInfo.setToken(cardInfo.getToken());
        cloverCardInfo.setExpMonth(cardInfo.getExpMonth());
        cloverCardInfo.setExpYear(cardInfo.getExpYear());
        cloverCardInfo.setFirst6(cardInfo.getFirst6());
        cloverCardInfo.setLast4(cardInfo.getLast4());
        cloverCardInfo.setBrand(cardInfo.getBrand());
        cloverCardInfo.setAddressLine1(cardInfo.getAddressLine1());
        cloverCardInfo.setAddressZip(cardInfo.getAddressZip());
        lumiereCloverCardInfoService.save(cloverCardInfo);
        return ResponseUtil.ok("添加成功");
    }

    @SneakyThrows(IOException.class)
    public Object deleteCustomer(String customerId,String cardId){
          OkHttpClient client = new OkHttpClient();
        //解除顾客卡绑定
        Request request = new Request.Builder()
                .url(String.format(LumiereCloverAPIConstant.CLOVER_DELETECUSTOMER,cloverConfig.getMerchantId(),customerId,cardId))
                .delete(null)
                .addHeader(LumiereCloverConstant.ACCEPT,LumiereCloverConstant.APPLICATIONJSON)
                .addHeader(LumiereCloverConstant.AUTHORIZATION, String.format(LumiereCloverConstant.BEARER,cloverConfig.getAccessToken()))
                .build();
        Response response = client.newCall(request).execute();
        return JSON.parseObject(response.body().string());
    }

    @SneakyThrows
    @Override
    public synchronized Object executePayment(String token,Integer userId,Integer orderId) {
        LitemallOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.fail(PaymentResponseCode.ORDER_UNKNOWN, "订单不存在");
        }
        //支付体
        ApiChargeRQ apiChargeRQ = new ApiChargeRQ();
        apiChargeRQ.setAmount(order.getActualPrice().multiply(new BigDecimal(100)));
        apiChargeRQ.setCurrency(DefaultCurType.CAD.getType());
        apiChargeRQ.setSource(token);
        apiChargeRQ.setStored_credentials(new ApiChargeDTO("SUBSEQUENT",true,"CARDHOLDER"));
        //apiChargeRQ.setSource(cloverCard.getCustomerId());
        //开始交易
        OkHttpClient client = new OkHttpClient();

        MediaType mediaType = MediaType.parse(LumiereCloverConstant.APPLICATIONJSON);
        RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(apiChargeRQ));
        Request request = new Request.Builder()
                .url(LumiereCloverAPIConstant.CLOVER_EXECUTEPAYMENT)
                .post(body)
                .addHeader(LumiereCloverConstant.ACCEPT,LumiereCloverConstant.APPLICATIONJSON)
                .addHeader(LumiereCloverConstant.CONTENTTYPE, LumiereCloverConstant.APPLICATIONJSON)
                .addHeader(LumiereCloverConstant.IDEMPOTENCYKEY, IdUtil.simpleUUID())
                .addHeader(LumiereCloverConstant.AUTHORIZATION, String.format(LumiereCloverConstant.BEARER,cloverConfig.getAccessToken()))
                .build();

        Response response = client.newCall(request).execute();
        JSONObject vo =  JSON.parseObject(response.body().string());
        CloverChargesDTO cloverChargesDTO = JSON.toJavaObject(vo,CloverChargesDTO.class);
        //支付失败
        if(StrUtil.isBlank(cloverChargesDTO.getId())){
            logger.info("clover card executePayment error : " + vo);
            String resultCode = StrUtil.sub(vo.getString("message"), 0, 3);
            return ResponseUtil.fail(Integer.parseInt(resultCode),vo.getString("error"));
        }
        long chargesLogId = IdUtil.createSnowflake(1, 1).nextId();
        //保存交易记录
        LumiereCloverChargesLog lumiereCloverChargesLog = LumiereCloverChargesLog.builder()
                .id(chargesLogId)
                .userId(userId)
                .shopId(order.getShopId())
                .transactionId(cloverChargesDTO.getId())
                .amount(order.getActualPrice())
                .amountRefunded(cloverChargesDTO.getAmount_refunded())
                .currency(cloverChargesDTO.getCurrency())
                .created(cloverChargesDTO.getCreated())
                .captured(cloverChargesDTO.getCaptured())
                .refNum(cloverChargesDTO.getRef_num())
                .authCode(cloverChargesDTO.getAuth_code())
                .networkStatus(cloverChargesDTO.getOutcome().getNetwork_status())
                .type(cloverChargesDTO.getOutcome().getType())
                .paid(cloverChargesDTO.getPaid())
                .status(cloverChargesDTO.getStatus())
                .customerId(cloverChargesDTO.getSource().getId())
                .addressLine1(cloverChargesDTO.getSource().getAddress_line1())
                .addressLine1Check(cloverChargesDTO.getSource().getAddress_line1_check())
                .addressZip(cloverChargesDTO.getSource().getAddress_zip())
                .addressZipCheck(cloverChargesDTO.getSource().getAddress_zip_check())
                .brand(cloverChargesDTO.getSource().getBrand())
                .expMonth(cloverChargesDTO.getSource().getExp_month())
                .expYear(cloverChargesDTO.getSource().getExp_year())
                .first6(cloverChargesDTO.getSource().getFirst6())
                .last4(cloverChargesDTO.getSource().getLast4())
                .orderId(orderId)
                .transactionType(1)
                .addTime(LocalDateTime.now())
                .deleted(false)
                .build();
        lumiereCloverChargesLogService.save(lumiereCloverChargesLog);
        // TODO 交易失败,可能是系统外部更改了customer绑定的token
        // 检查这个订单是否已经处理过
        if (OrderStatusUtil.isPayStatus(order) || order.getPayId() != null) {
            return ResponseUtil.fail(PaymentResponseCode.PAYMENT_FAIL, "订单已经处理成功!");
        }
        // 检查支付订单金额
        /*BigDecimal totalFee = vo.getBigDecimal("amount");
        if (totalFee.compareTo(order.getActualPrice().multiply(new BigDecimal(100))) != 0) {
            return ResponseUtil.fail(PaymentResponseCode.PAYMENT_FAIL, " : 支付金额不符合 totalFee=" + totalFee);
        }*/

        order.setPayType(Constants.PAY_TYPE_CLOVER);
        order.setCurrency(DefaultCurType.CAD.getType());
        order.setTransationId(cloverChargesDTO.getId());
        order.setPayTime(LocalDateTime.now());
        order.setOrderStatus(Constants.ORDER_STATUS_ONGOING);
        order.setMadeStatus(Constants.ORDER_MADE_STATUS_NEW);
        logger.debug("更新订单信息");
        //orderService.updateById(order);
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            order = orderService.findBySn(order.getOrderSn());
            if (OrderStatusUtil.isCancelStatus(order)) {
                order.setPayTime(LocalDateTime.now());
                order.setOrderStatus(Constants.ORDER_STATUS_ONGOING);
                order.setMadeStatus(Constants.ORDER_MADE_STATUS_NEW);//更新订单状态为待制作
                if (orderService.updateWithOptimisticLocker(order) == 0) {
                    return ResponseUtil.updatedDateExpired();
                }
            }
        }
        //记录交易
        LumiereCloverPayLog cloverPayLog = new LumiereCloverPayLog();
        cloverPayLog.setExternalId(orderId.toString());
        cloverPayLog.setOrderId(cloverChargesDTO.getId());
        cloverPayLog.setPaymentId(cloverChargesDTO.getId());
        cloverPayLog.setCardNo(cloverChargesDTO.getSource().getLast4().toString());
        cloverPayLog.setCardType(cloverChargesDTO.getSource().getBrand());
        cloverPayLog.setAddTime(LocalDateTime.now());
        cloverPayLog.setUpdateTime(LocalDateTime.now());
        cloverPayLog.setDeleted(false);
        lumiereCloverPayLogService.add(cloverPayLog);
        //给用户发送系统订单通知
        noticeHelper.noticeUser(Constants.MSG_TYPE_ORDER, LumiereCloverConstant.WX_ORDER_TITLE_NOTICEHELPER, String.format(LumiereCloverConstant.WX_ORDER_NOTICEHELPER,order.getOrderSn()),userId,order);
        return cloverChargesDTO;
    }
    @SneakyThrows
    @Override
    public Object getPayment(Integer userId, Integer orderId, String successUrl, String cancelUrl) {

        return null;
    }
    @Override
    public boolean refund(Integer orderId) throws IOException {
        //获取最新的商家令牌(令牌有效期一年)
        List<LumiereCloverCode> cloverCodeList = lumiereCloverCodeService.list(Wrappers.lambdaQuery(LumiereCloverCode.class).orderByDesc(LumiereCloverCode::getAddTime));
        LumiereCloverCode cloverCode = cloverCodeList.get(cloverCodeList.size()-1);

        LitemallOrder order = orderService.findById(orderId);
        ApiRefundRQ apiRefundRQ = new ApiRefundRQ();
        if (order.getTransationId() == null) {
            return false;
        } else {
            apiRefundRQ.setCharge(order.getTransationId());
            apiRefundRQ.setAmount(order.getActualPrice());
            apiRefundRQ.setReason("fraudulent");

            OkHttpClient client = new OkHttpClient();

            MediaType mediaType = MediaType.parse("application/json");
            RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(apiRefundRQ));
            Request request = new Request.Builder()
                    .url("https://scl-sandbox.dev.clover.com/v1/refunds")
                    .post(body)
                    .addHeader("Accept", "application/json")
                    .addHeader("Content-Type", "application/json")
                    .addHeader("Authorization", "Bearer "+cloverCode.getAccessToken())
                    .build();

            Response response = client.newCall(request).execute();
            JSONObject vo = (JSONObject) JSON.parse(response.body().string());
            if (vo.getString("status").equals("succeeded")) {
                return true;
            } else {
                return false;
            }
        }
    }

    public ApiKeyRS getKeyRS() throws IOException {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url("https://apisandbox.dev.clover.com/pakms/apikey")
                .get()
                .addHeader("Accept", "application/json")
                .addHeader("Authorization", "Bearer 9794412f-b946-5652-9d70-c2083e586408")
                .build();

        Response response = client.newCall(request).execute();

        JSONObject vo = (JSONObject) JSON.parse(response.body().string());

        ApiKeyRS keyVo = new ApiKeyRS();
        keyVo.setActive((Boolean) vo.get("active"));
        keyVo.setApiAccessKey(vo.getString("apiAccessKey"));
        keyVo.setMerchantUuid(vo.getString("merchantUuid"));
        keyVo.setDeveloperAppUuid(vo.getString("developerAppUuid"));
        keyVo.setCreatedTime(vo.getString("createdTime"));
        keyVo.setModifiedTime(vo.getString("modifiedTime"));
        return keyVo;
    }

    public ApiTokenRS getTokenRS(String cardNo, String month, String year, String cvv, String brand, String name,
                                 String address_line1, String address_line2, String address_city, String address_state,
                                 String address_zip, String address_country) throws IOException {
        OkHttpClient client = new OkHttpClient();
        ApiKeyRS keyRS = getKeyRS();
        ApiCardRQ cardRQ = new ApiCardRQ();
        cardRQ.setNumber(cardNo);
        cardRQ.setExp_month(month);
        cardRQ.setExp_year(year);
        cardRQ.setCvv(cvv);
        cardRQ.setBrand(brand);
        cardRQ.setLast4(cardRQ.getNumber().substring(cardRQ.getNumber().length() - 4, cardRQ.getNumber().length()));
        cardRQ.setFirst6(cardRQ.getNumber().substring(0, 6));
//        cardRQ.setAddress_line1(address_line1);
//        cardRQ.setAddress_line2(address_line2);
//        cardRQ.setAddress_city(address_city);
//        cardRQ.setAddress_state(address_state);
//        cardRQ.setAddress_zip(address_zip);
//        cardRQ.setAddress_country(address_country);

        ApiTokenRQ rq = new ApiTokenRQ();
        rq.setCard(cardRQ);

        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(rq));
        Request request = new Request.Builder()
                .url("https://token-sandbox.dev.clover.com/v1/tokens")
                .post(body)
                .addHeader("Accept", "application/json")
                .addHeader("apikey", keyRS.getApiAccessKey())
                .addHeader("Content-Type", "application/json")
                .build();

        Response response = client.newCall(request).execute();
        JSONObject vo = (JSONObject) JSON.parse(response.body().string());
        ApiTokenRS tokenVo = new ApiTokenRS();
        tokenVo.setId(vo.getString("id"));

        return tokenVo;
    }

    public void presentPoint(Integer orderId) {
        LitemallOrder order = orderService.findById(orderId);
        Integer cityRegionId = getShopRegionId(order.getShopId());
        if (order != null) {
            Integer userId = order.getUserId();
            LitemallUser user = litemallUserService.findById(userId);

            if (user != null) {
                Byte userLevel = user.getUserLevel();
                //等级会员
                BigDecimal obtainPoint = BigDecimal.ZERO;

                //付费会员赠送积分   判断是否过期
                List<LumierePayMemberUser> payMemberUsers = lumierePayMemberUserService.listUsers(userId, null);
                for (int i = 0; i < payMemberUsers.size(); i++) {
                    //判断是否过期
                    if (payMemberUsers.get(i).getEndTime().compareTo(LocalDateTime.now()) > 0) {
                        LumierePayMember payMember = lumierePayMemberService.findById(payMemberUsers.get(i).getPayMemberId());

                        boolean flag = false;
                        if(payMember.getShopIds() != null){
                            for (int j = 0; j < payMember.getShopIds().length; j++) {
                                if (payMember.getShopIds()[j].equals(cityRegionId)) {
                                    flag = true;
                                }
                            }
                        }else{
                            flag =  true;
                        }

                        if(payMember.getPointRatio() != null && payMember.getPointRatio() != 0 && flag){
                            if(obtainPoint.compareTo(BigDecimal.ZERO) == 0){
                                obtainPoint = order.getActualPrice().multiply(new BigDecimal(payMember.getPointRatio()));
                            }else if(obtainPoint.compareTo(order.getActualPrice().multiply(new BigDecimal(payMember.getPointRatio()))) < 0){
                                obtainPoint = order.getActualPrice().multiply(new BigDecimal(payMember.getPointRatio()));
                            }
                        }
                    }
                }

                LumiereLevelMember levelMember = lumierelLevelMemberService.findById(userLevel.intValue());
                if (levelMember.getPointRatio() != null && levelMember.getPointRatio() != 0) {
                    obtainPoint = obtainPoint.add(order.getActualPrice().multiply(new BigDecimal(levelMember.getPointRatio())));
                }

                //用户添加积分
                user.setPoints(user.getPoints().add(obtainPoint));

                //积分记录

                userService.updateById(user);

                LitemallIntegralLog log = new LitemallIntegralLog();
                log.setUserId(userId);
                log.setType(Constants.INTEGRAL_LOG_TYPE_ADD);
                log.setPoints(user.getPoints());
                log.setChangePoints(obtainPoint);


                integralLogService.add(log);

                LitemallOrder update = new LitemallOrder();
                update.setPoints(obtainPoint);
                update.setId(order.getId());
                orderService.updateByIdEx(update);
            }
        }
    }

    /**
     * 用户购买，等级会员升级
     */
    public void upgradeUserLevel(Integer orderId) {
        LitemallOrder order = orderService.findById(orderId);
        Integer userId = order.getUserId();
        LitemallUser user = litemallUserService.findById(userId);

        //用户当前等级
        LumiereLevelMember levelMember = lumierelLevelMemberService.findById(user.getUserLevel().intValue());

        LumiereLevelMemberExample example = new LumiereLevelMemberExample();
        example.or().andPidEqualTo(levelMember.getId());

        List<LumiereLevelMember> nexts = lumierelLevelMemberService.list(example);

        //记录用户的积分
        List<LumiereLevelMemberPoint> points = lumiereLevelMemberPointService.listByUserId(userId);
        LumiereLevelMember upgradMember = lumierelLevelMemberService.queryByPidInDel(user.getUserLevel().intValue());
        //向上升级，查找升级的等级没有被删除，且状态为启用
        while (upgradMember != null && (upgradMember.getDeleted() == true || upgradMember.getStatus().equals(MEMBER_STATUS_INUSE) == false)) {
            upgradMember = lumierelLevelMemberService.queryByPid(upgradMember.getId());
        }
        if (points.size() == 0) {
            LumiereLevelMemberPoint point = new LumiereLevelMemberPoint();
            point.setConsumptionMoney(order.getActualPrice());

            point.setStartTime(LocalDateTime.now());
            if (levelMember != null && levelMember.getExpiredDays() != 0) {
                //point.setEndTime(LocalDateTime.of(LocalDate.now(), LocalTime.MAX).plusDays(levelMember.getExpiredDays()));
                point.setEndTime(LocalDateTime.now().plusDays(levelMember.getExpiredDays()));
            }
            point.setUserId(userId);
            point.setAddTime(LocalDateTime.now());
            point.setUpdateTime(LocalDateTime.now());
            point.setConsumptionMoney(order.getActualPrice());
            point.setDeleted(false);


            point.setConsumptionPoints(new BigDecimal(0.00).setScale(2,BigDecimal.ROUND_HALF_UP));

            //如果没有符合条件的就不升级
            if ( upgradMember != null &&  (upgradMember.getDeleted() == false && upgradMember.getStatus().equals(MEMBER_STATUS_INUSE) == true)) {
                if (levelMember.getUpgradeMoney() != null && levelMember.getUpgradeMoney().compareTo(order.getActualPrice()) <= 0) {
                    user.setUserLevel(upgradMember.getId().byteValue());
                    point.setConsumptionMoney(new BigDecimal(0));
                    //会员升级
                    userService.updateById(user);

                    //用户等级会员升级，赠送福利
                    LocalDateTime endT = upgradMember.getExpiredDays() != null ? LocalDateTime.now().plusDays(upgradMember.getExpiredDays()) : null;
                    welfareGift(upgradMember.getId(), null, null, userId, upgradMember, endT);
                     noticeHelper.noticeUser(Constants.MSG_TYPE_OTHER,
                            LitemallWXMembershipLevelConstants.WX_MEMBERSHIP_LEVEL_TITLE_NOTICEHELPER,
                            String.format(LitemallWXMembershipLevelConstants.WX_MEMBERSHIP_LEVEL_UPGRADE_NOTICEHELPER,upgradMember.getName()),userId,upgradMember);
                }
            }
            lumiereLevelMemberPointService.add(point);
        } else {
            //用户会员等级的变化
            LumiereLevelMemberPoint point = points.get(0);
            if ( upgradMember != null && (upgradMember.getDeleted() == false && upgradMember.getStatus().equals(MEMBER_STATUS_INUSE) == true)) {
                if (levelMember.getUpgradeMoney() != null && levelMember.getUpgradeMoney().compareTo(order.getActualPrice().add(point.getConsumptionMoney())) <= 0) {
//                    LumiereLevelMemberExample ex2 = new LumiereLevelMemberExample();
//                    ex2.or().andPidEqualTo(user.getUserLevel().intValue());
//                    List<LumiereLevelMember> list = lumierelLevelMemberService.list(ex2);
                    user.setUserLevel(upgradMember.getId().byteValue());

                    userService.updateById(user);
//                     points.get(0).setConsumptionMoney(new BigDecimal(0));
                    //更改会员积分使用记录
                    if (upgradMember.getExpiredDays() != null && upgradMember.getExpiredDays() != 0) {
                        point.setStartTime(LocalDateTime.now());
                        point.setEndTime(LocalDateTime.now().plusDays(upgradMember.getExpiredDays()));
                        //point.setEndTime(LocalDateTime.of(LocalDate.now(), LocalTime.MAX).plusMonths(1));
                    } else {
                        point.setEndTime(point.getEndTime());
                    }


                    LocalDateTime endT = upgradMember.getExpiredDays() != null ? LocalDateTime.now().plusDays(upgradMember.getExpiredDays()) : null;
                    welfareGift(upgradMember.getId(), null, null, userId, upgradMember, endT);

                     noticeHelper.noticeUser(Constants.MSG_TYPE_OTHER,
                            LitemallWXMembershipLevelConstants.WX_MEMBERSHIP_LEVEL_TITLE_NOTICEHELPER,
                            String.format(LitemallWXMembershipLevelConstants.WX_MEMBERSHIP_LEVEL_UPGRADE_NOTICEHELPER,upgradMember.getName()),userId,upgradMember);
                    point.setConsumptionMoney(BigDecimal.ZERO);
                } else {
                    point.setConsumptionMoney(point.getConsumptionMoney().add(order.getActualPrice()));
                    point.setEndTime(point.getEndTime());
                }
                lumiereLevelMemberPointService.update(point);
            }
        }
    }

    public void welfareGift(Integer memberId, LitemallUser giveeUser,
                            String userName, Integer userId, LumiereLevelMember levelMember, LocalDateTime endT) {
        //新优惠券
        List<LumiereCouponStrategy> lumiereCouponStrategies = lumiereCouponStrategyService.list(Wrappers.lambdaQuery(LumiereCouponStrategy.class)
                .eq(LumiereCouponStrategy::getCouponType, 5)
                .eq(LumiereCouponStrategy::getStatus, 1)
                .eq(LumiereCouponStrategy::getDeleted, 0));
        lumiereCouponStrategies.stream().forEach(lumiereCouponStrategy->{
            for (Integer levelMemberId : lumiereCouponStrategy.getLevelMember()){
                if(levelMemberId.equals(memberId)){
                    for(int i=1;i<=(lumiereCouponStrategy.getReleasedQuantity()==null?1:lumiereCouponStrategy.getReleasedQuantity());i++){
                    long nextId = IdUtil.getSnowflake(2, 2).nextId();
                    LocalDateTime[] localDateTimes = AdminCouponDateUtil.calculateExpirationTime(lumiereCouponStrategy);
                    //发放券
                    LumiereCouponUser coupon = LumiereCouponUser.builder()
                            .userId(userId)
                            .strategyId(lumiereCouponStrategy.getId())
                            .couponId(lumiereCouponStrategy.getCouponId())
                            .userName(userName)
                            .startTime(localDateTimes[0])
                            .endTime(localDateTimes[1])
                            .code(String.valueOf(nextId))
                            .addTime(LocalDateTime.now())
                            .updateTime(LocalDateTime.now())
                            .deleted(false)
                            .build();
                    lumiereCouponUserService.save(coupon);
                }
            }}
        });




        //添加优惠券
        List<LumiereMemberWelfareCoupon> welfareCoupons = lumiereMemberWelfareCouponService.findByMemberId(memberId, (byte) 1);

        welfareCoupons.stream().forEach(welfareCoupon -> {
            Integer couponNum = welfareCoupon.getNumbers();
            LitemallCoupon coupon = litemallCouponService.findById(welfareCoupon.getCouponId());

            if (coupon != null) {
                LocalDateTime startT = coupon.getStartTime();
                LocalDateTime endTime = coupon.getEndTime();
                if(coupon.getTimeType().equals(0)){
                    startT = LocalDateTime.now();
                    endTime = startT.plusDays(coupon.getDays());
                }

                for (Integer i = 0; i < couponNum; i++) {
                    LitemallCouponUser litemallCouponUser = new LitemallCouponUser();
                    litemallCouponUser.setStartTime(startT);
                    litemallCouponUser.setEndTime(endTime);
                    litemallCouponUser.setStatus((short) 0);
                    litemallCouponUser.setCouponId(coupon.getId());
                    litemallCouponUser.setAddTime(LocalDateTime.now());
                    litemallCouponUser.setUpdateTime(LocalDateTime.now());
                    litemallCouponUser.setDeleted(false);
                    litemallCouponUser.setUserId(giveeUser != null ? giveeUser.getId() : userId);
                    litemallCouponUser.setUserName(userName);
                    litemallCouponUserService.add(litemallCouponUser);
                }
            }
        });

        //添加用户订阅
        List<LumiereMemberWelfareSubscribe> welfareSubscribes = lumiereMemberWelfareSubscribeService.findByMemberId(memberId, (byte) 1);

        welfareSubscribes.stream().forEach(welfareSubscribe -> {
            Integer[] selectRuleIds = welfareSubscribe.getSubscribeRuleIds();
            LumiereSubscribeUser subscribeUser = addSubscribeUser(userId, welfareSubscribe.getSubscribeId(), selectRuleIds, endT, userName, giveeUser);
            lumiereSubscribeUserService.add(subscribeUser);
        });


        //添加礼物卡
        if (levelMember.getGiftCardIds() != null) {
            Integer[] giftCardIds = levelMember.getGiftCardIds();
            for (int i = 0; i < giftCardIds.length; i++) {
                LitemallGiftCard litemallGiftCard = litemallGiftCardService.findById(giftCardIds[i]);
                if (litemallGiftCard != null) {
                    LitemallGiftCardUser giftCardUser = new LitemallGiftCardUser();
                    giftCardUser.setIsDefault(0);

                    String cardNumber = GeneratorUtil.cardNumberGenerator("00", userId);
                    LitemallGiftCardUser cardUser = litemallGiftCardUserService.findByNumber(cardNumber);
                    while (cardUser != null) {
                        cardNumber = GeneratorUtil.cardNumberGenerator("00", userId);
                        cardUser = litemallGiftCardUserService.findByNumber(cardNumber);
                    }
                    giftCardUser.setCardNumber(cardNumber);
                    giftCardUser.setUserId(giveeUser != null ? giveeUser.getId() : userId);
                    giftCardUser.setAmount(BigDecimal.ZERO);
                    giftCardUser.setStatus(0);
                    giftCardUser.setBindTime(LocalDateTime.now());
                    giftCardUser.setDeleted(false);
                    giftCardUser.setAddTime(LocalDateTime.now());
                    giftCardUser.setUpdateTime(LocalDateTime.now());
                    giftCardUser.setGiftCardId(giftCardIds[i]);
                    litemallGiftCardUserService.add(giftCardUser);
                }
            }
        }

    }

    public boolean beforeCreate(String cardNo,Integer userId) throws IOException {
        ApiChargeRQ apiChargeRQ = new ApiChargeRQ();
        apiChargeRQ.setAmount(new BigDecimal(0));
        apiChargeRQ.setCurrency("CAD");
        String cloverToken = CloverTokenManager.getCloverToken(cardNo,userId);

        if(cloverToken == null){
            return false;
        }
        apiChargeRQ.setSource(cloverToken);

        OkHttpClient client = new OkHttpClient();

        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(apiChargeRQ));
        Request request = new Request.Builder()
                .url("https://scl-sandbox.dev.clover.com/v1/charges")
                .post(body)
                .addHeader("Accept", "application/json")
                .addHeader("Content-Type", "application/json")
                .addHeader("Authorization", "Bearer 9794412f-b946-5652-9d70-c2083e586408")
                .build();

        Response response = client.newCall(request).execute();
        JSONObject vo = (JSONObject) JSON.parse(response.body().string());
        ApiChargeRS apiChargeRS = new ApiChargeRS();
        apiChargeRS.setSource(vo.getObject("source", ApiTokenSourceRS.class));

        //&& apiChargeRS.getSource().getAddress_zip_check().equals("pass")
//        if(apiChargeRS.getSource() != null && apiChargeRS.getSource().getAddress_line1_check() != null &&
//                apiChargeRS.getSource().getAddress_line1_check().equals("pass")&& apiChargeRS.getSource().getAddress_zip_check() != null ){
//            return true;
//        }

        if (vo != null || vo.getString("error") != null) {
            if (vo.getString("status").equals("succeeded")) {
                return true;
            }
        }


        return false;
    }

    public LumiereSubscribeUser addSubscribeUser(Integer userId, Integer subscribeId, Integer[] selectRuleIds,
                                                 LocalDateTime endT, String givee, LitemallUser giveeUser) {

        LitemallUser user = litemallUserService.findById(userId);

        LumiereSubscribeUser lumiereSubscribeUser = new LumiereSubscribeUser();
        lumiereSubscribeUser.setPurchaserId(userId);
        if (lumiereSubscribeUser.getUserId() == null) {
            lumiereSubscribeUser.setUserId(giveeUser != null ? giveeUser.getId() : userId);
        }

        LumiereSubscribeRule rule = lumiereSubscribeRuleService.findById(selectRuleIds[0]);

        lumiereSubscribeUser.setSubscribeId(subscribeId);

        lumiereSubscribeUser.setStatus(Constants.SUBSCRIBE_USER_MEMBER_NOT_CONFIRM);

        lumiereSubscribeUser.setAutoSub(false);

        lumiereSubscribeUser.setPurchaserId(giveeUser != null ? giveeUser.getId() : userId);

        lumiereSubscribeUser.setUserName(giveeUser != null ? giveeUser.getUsername() : user != null ? user.getUsername() : null);

        lumiereSubscribeUser.setPrice(BigDecimal.ZERO);

        lumiereSubscribeUser.setStartTime(LocalDateTime.now());

        if(rule != null) {
            if (rule.getRuleType().equals((byte) 1)) {
                lumiereSubscribeUser.setEndTime(LocalDateTime.now().plusWeeks(1));
            } else if (rule.getRuleType().equals((byte) 2)) {
                lumiereSubscribeUser.setEndTime(LocalDateTime.now().plusMonths(1));
            } else {
                lumiereSubscribeUser.setEndTime(LocalDateTime.now().plusYears(1));
            }
        }
        lumiereSubscribeUser.setRuleId(selectRuleIds[0]);

        return lumiereSubscribeUser;
    }

    private Integer getShopRegionId(Integer shopId) {
        List<LitemallShopRegion> litemallShopRegions = shopRegionService.queryByShopId(shopId);
        if (!CollectionUtils.isEmpty(litemallShopRegions)) {
            for (LitemallShopRegion litemallShopRegion : litemallShopRegions) {
                LitemallRegion litemallRegion = regionService.findById(litemallShopRegion.getRegionId());
                if (Constants.REGION_TYPE_CITY == litemallRegion.getType()) {
                    return litemallShopRegion.getRegionId();
                }
            }
        }
        return null;
    }


}
